package com.cby.android.olive.utils

import android.util.Log
import java.lang.Exception
import java.util.regex.Pattern
import android.content.ContentValues.TAG
import android.content.Context
import java.io.*
import java.net.InetAddress
import java.net.URL
import java.text.SimpleDateFormat
import java.util.*

object PingUtils {


    /**
     * Jdk1.5的InetAddresss,代码简单
     * @param ipAddress
     * @throws Exception
     */

    @JvmStatic
    fun ping(ipAddress: String?, timeOut:Int = 3000, callback: ((boolean: Boolean) -> Unit)? = null) {
        val runnable = Runnable {
            try {
                // 当返回值是true时，说明host是可用的，false则不可。
                val isReachable = InetAddress.getByName(ipAddress)
                    .isReachable(timeOut)
                if (callback != null) {
                    callback(isReachable)
                }
            }catch (e:Exception) {
                if (callback != null) {
                    callback(false)
                }
            }

        }
        Thread(runnable).start()
    }

    /**
     * 使用java调用cmd命令,这种方式最简单，可以把ping的过程显示在本地。ping出相应的格式
     * @param url
     * @throws Exception
     */
    @Throws(Exception::class)
    @JvmStatic
    fun ping1(context: Context, url: String?) {
        var line: String? = null
        // 获取主机名
        val transUrl: URL?
        // getExternalFilesDir("logs") = /storage/emulated/0/Android/data/packageName/files/logs
        val logFilePath = context.getExternalFilesDir("logs")?.absolutePath
        try {
            transUrl = URL(url)
            val hostName: String = transUrl.host
            Log.e(TAG, "hostName: $hostName")
            val runtime = Runtime.getRuntime()
            val process = runtime.exec("ping $hostName")
            val buf = BufferedReader(InputStreamReader(process.inputStream))
            while (buf.readLine()?.also { line = it } != null) {
                if (line!!.isNotEmpty() && line!!.indexOf("time=") > 0) {
                    val content = line!!.substring(line!!.indexOf("time="))
                    val index = content.indexOf("time=")
                    val str = content.substring(index + 5, index + 9)
                    Log.e(TAG, "time=: $str")
                    val result: String = SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())
                        .toString() + ", " + hostName + ", " + str + "\r\n"
                    Log.e(TAG, "result: $result")
                    createPingFile(logFilePath!!, result)
                }
            }
        } catch (ex: Exception) {
            println(ex.message)
        }
    }

    /**
     * 创建ping的数据文件
     * @param path String
     * @param text String
     */
    private fun  createPingFile(path: String, text: String) {
        //synchronized(this){
        val appDir = File(path)
        if (!appDir.exists()) {
            appDir.mkdirs()
        }
        val df = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
        val date: String = df.format(Date())
        val fileName = "$date.txt"
        val file = File(appDir, fileName)
        if (!file.exists()) {
            file.createNewFile()
        }
        try
        {
            //BufferedWriter for performance, true to set append to file flag
            val buf = BufferedWriter( OutputStreamWriter(FileOutputStream(file, true), "gbk"))
            buf.append(text)
            buf.newLine()
            buf.close()
        }
        catch (e:IOException)
        {
            e.printStackTrace();
        }
        //}

    }

    /**
     * 使用java调用控制台的ping命令，这个比较可靠，还通用，使用起来方便：传入个ip，设置ping的次数和超时，就可以根据返回值来判断是否ping通。
     * ping 127.0.0.1 -n 10 -w 4
     * @param ipAddress ping的IP地址
     * @param pingTimes ping的次数
     * @param timeOut ping的时候超时的时长
     */
    @JvmStatic
    fun ping2(ipAddress: String, pingCallback: ((resultLine: String)->Unit)? = null) {

        val runnable = Runnable {
            var `in`: BufferedReader? = null
            // 将要执行的ping命令,此命令是windows格式的命令
            val r = Runtime.getRuntime()
            val pingCommand = spellPing(ipAddress)
            try {
                // 执行命令并获取输出
                println(pingCommand)
                val p = r.exec(pingCommand)
                // 逐行检查输出,计算类似出现=23ms TTL=62字样的次数
                `in` = BufferedReader(InputStreamReader(p.inputStream))

                var line: String? = null
                while (`in`.readLine().also { line = it } != null) {
                    Log.i("AppUtils", "控制台输出的结果为:$line")
                    if (pingCallback != null) {
                        // 类似=23ms TTL=62这样的字样,出现的次数=测试次数则返回真
                        pingCallback(line!!)
                    }
                }
            } catch (ex: Exception) {
                ex.printStackTrace() // 出现异常则返回假
            } finally {
                try {
                    `in`!!.close()
                } catch (e: IOException) {
                    e.printStackTrace()
                }
            }

        }
        Thread(runnable).start()

    }

    private fun spellPing(ip: String): String? {
        val countCmd = " -c 5 "
        val timeCmd = " -w 7 "
        return "ping$countCmd$timeCmd$ip"
    }

    /**
     *  若line含有=18ms TTL=16字样,说明已经ping通,返回1,否則返回0.
     */
    private fun getCheckResult(line: String): String {
        Log.i("AppUtils", "控制台输出的结果为:$line")
        val pattern = Pattern.compile("(\\d+ms)(\\s+)(TTL=\\d+)", Pattern.CASE_INSENSITIVE)
        val matcher = pattern.matcher(line)
        while (matcher.find()) {
            return line
        }
        return ""
    }
}